﻿using System;
using System.Collections.Generic;
using System.Text;
using Oragon.Architecture.Data.SqlBuilder.Operators;
using System.Xml.Serialization;

namespace Oragon.Architecture.Data.SqlBuilder
{
	[Serializable]
	public class SelectSQLBuilder : ISQLStatement, ICloneble<SelectSQLBuilder>
	{
		#region Propriedades

		/// <summary>
		/// Determina as tabelas envolvidas no FROM da colsup
		/// </summary>
		public List<FromItem> Tables { get; set; }

		/// <summary>
		/// Determina as colunas a serem exibidas
		/// </summary>
		public List<ColumnItem> Columns { get; set; }

		public TopClause TopClause { get; set; }

		public List<OrderByItem> OrderBy { get; set; }

		public WhereClause WhereClause { get; set; }

		#endregion

		public SelectSQLBuilder()
		{
			this.Columns = new List<ColumnItem>();
			this.Tables = new List<FromItem>();
			this.WhereClause = new WhereClause();
			this.OrderBy = new List<OrderByItem>();
			this.TopClause = new TopClause(100, TopUnit.Percent);
		}


		private FromItem GetDefaultTable(bool thowExceptionWhenNotFound)
		{
			FromItem returnValue = null;
			if (this.Tables.Count == 1)
			{
				returnValue = this.Tables[0];
			}
			else if (thowExceptionWhenNotFound)
			{
				throw new AliasNotFoundException("Não foi possível identificar a tabela padrão da consulta.");
			}
			return returnValue;
		}


		public SelectSQLBuilder Clone()
		{
			System.Runtime.Serialization.Formatters.Binary.BinaryFormatter serializer = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
			System.IO.MemoryStream stream = new System.IO.MemoryStream();
			serializer.Serialize(stream, this);
			stream.Position = 0;
			SelectSQLBuilder newInstance = (SelectSQLBuilder)serializer.Deserialize(stream);
			stream.Close();
			return newInstance;
			
			//XmlSerializer serializer = new XmlSerializer(typeof(SelectSQLBuilder));
			//System.IO.MemoryStream stream = new System.IO.MemoryStream();
			//serializer.Serialize(stream, this);
			//stream.Position = 0;
			//SelectSQLBuilder newInstance = (SelectSQLBuilder)serializer.Deserialize(stream);
			//stream.Close();
			//return newInstance;
		}

		public string ToSQL()
		{
			System.IO.StringWriter SQL = new System.IO.StringWriter(System.Globalization.CultureInfo.InvariantCulture);
			SQL.WriteLine("SELECT {0}", this.TopClause.ToSQL());
			if (this.Columns.Count == 0)
			{
				SQL.WriteLine("	* ");
			}
			else
			{
				for (int columnIndex = 0; columnIndex < this.Columns.Count; columnIndex++)
				{
					SQL.WriteLine("	{1}{0}", this.Columns[columnIndex].ToSQL(), (columnIndex != 0) ? "," : string.Empty);
				}
			}
			if (this.Tables.Count > 0)
			{
				SQL.WriteLine("FROM ");
				for (int tableIndex = 0; tableIndex < this.Tables.Count; tableIndex++)
				{
					SQL.WriteLine("	{1}{0}", this.Tables[tableIndex].ToSQL(), (tableIndex != 0) ? "," : string.Empty);
				}
			}
			SQL.Write(this.WhereClause.ToSQL());

			bool isFirst = true;
			if (this.OrderBy.Count > 0)
			{
				SQL.WriteLine("ORDER BY");
				SQL.Write("	");
				foreach (OrderByItem orderByItem in this.OrderBy)
				{
					if (isFirst)
					{
						isFirst = false;
						SQL.Write(orderByItem.ToSQL());
					}
					else
					{
						SQL.Write(", {0}", orderByItem.ToSQL());
					}
				}
			}

			return SQL.ToString();
		}

	}
}
